package com.xmmj.baselibrary.utils.adapter.recyclerview;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.CallSuper;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.databinding.DataBindingUtil;
import androidx.databinding.ObservableList;
import androidx.databinding.ViewDataBinding;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.xmmj.baselibrary.R;
import com.xmmj.baselibrary.base.application.BaseApplication;

import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.List;

import me.tatarka.bindingcollectionadapter2.BindingCollectionAdapter;
import me.tatarka.bindingcollectionadapter2.BindingRecyclerViewAdapter;
import me.tatarka.bindingcollectionadapter2.ItemBinding;

public class WithEmptyViewBindingAdapter<T> extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements BindingCollectionAdapter<T> {
    private static final Object DATA_INVALIDATION = new Object();

    protected ItemBinding<? super T> itemBinding;
    protected List<T> dataSource;
    private Handler myHandler;
    // 0-不显示空布局 1-显示空布局
    protected int isEmptyState = 0;
    //外部配置是否显示空布局页属性  默认不显示
    private boolean enableShowEmptyView;
    protected RecyclerView.LayoutManager layoutManager;
    private ItemIds<? super T> itemIds;
    protected ViewHolderFactory viewHolderFactory;
    private WeakReferenceOnListChangedCallback<T> callback;
    private RecyclerView recyclerView;
    private INoDataView emptyView;
    private LayoutInflater inflater;
    private final int empty_view_type = -1;
    private LifecycleOwner lifecycleOwner;
    private boolean initSetting;
    //0-默认无数据空页面 1-网络异常空页面
    private int noDataType;

    public WithEmptyViewBindingAdapter() {
    }

    /**
     * Constructs a new instance with the given item binding.
     */
    public WithEmptyViewBindingAdapter(@NonNull ItemBinding<? super T> itemBinding) {
        this.itemBinding = itemBinding;
    }

    @Override
    public void setItemBinding(@NonNull ItemBinding<? super T> itemBinding) {
        this.itemBinding = itemBinding;
    }

    @NonNull
    @Override
    public ItemBinding<? super T> getItemBinding() {
        return this.itemBinding;
    }

    @Override
    public void setItems(@Nullable List<T> items) {
        initSetting = dataSource == null;
        if (this.dataSource == items) {
            return;
        }
        // If a recyclerview is listening, set up listeners. Otherwise wait until one is attached.
        // No need to make a sound if nobody is listening right?
        if (recyclerView != null) {
            if (this.dataSource instanceof ObservableList) {
                ((ObservableList<T>) this.dataSource).removeOnListChangedCallback(callback);
                callback = null;
            }
            if (items instanceof ObservableList) {
                callback = new WeakReferenceOnListChangedCallback<>(this, (ObservableList<T>) items);
                ((ObservableList<T>) items).addOnListChangedCallback(callback);
            }
        }
        this.dataSource = items;
        this.notifyDataSetChanged();
    }

    public List<T> getDataSource() {
        return dataSource;
    }

    @Override
    public T getAdapterItem(int position) {
        return dataSource == null || dataSource.size() == 0 ? null : dataSource.get(position);
    }

    @NonNull
    @Override
    public ViewDataBinding onCreateBinding(@NonNull LayoutInflater inflater, int layoutId, @NonNull ViewGroup viewGroup) {
        ViewDataBinding viewDataBinding = DataBindingUtil.inflate(inflater, layoutId, viewGroup, false);
        return viewDataBinding;
    }

    @Override
    public void onBindBinding(@NonNull ViewDataBinding binding, int variableId, int layoutRes, int position, T item) {
        tryGetLifecycleOwner();
        if (itemBinding.bind(binding, item)) {
            binding.executePendingBindings();
            if (lifecycleOwner != null) {
                binding.setLifecycleOwner(lifecycleOwner);
            }
        }
    }


    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int layoutId) {
        initLayoutManage();
        if (inflater == null) {
            inflater = LayoutInflater.from(parent.getContext());
        }
        if (layoutId == empty_view_type) {
            if (emptyView == null || emptyView.getView() == null) {
                emptyView = new NoDataView(parent.getContext(), null);
            }
            adjustEmptyViewSize();
            return new EmptyViewHolder(emptyView.getView());
        } else {
            ViewDataBinding binding = onCreateBinding(inflater, layoutId, parent);
            return onCreateViewHolder(binding);
        }
    }

    /**
     * Constructs a view holder for the given databinding. The default implementation is to use
     * {@link BindingRecyclerViewAdapter.ViewHolderFactory} if provided, otherwise use a default view holder.
     */
    public RecyclerView.ViewHolder onCreateViewHolder(ViewDataBinding binding) {
        if (viewHolderFactory != null) {
            return viewHolderFactory.createViewHolder(binding);
        } else {
            return new BindingViewHolder(binding);
        }
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
// This won't be called by recyclerview since we are overriding the other overload, call
        // the other overload here in case someone is calling this directly ex: in a test.
        if (viewHolder instanceof EmptyViewHolder) {
            return;
        }
        onBindViewHolder(viewHolder, position, Collections.emptyList());
    }

    @Override
    @CallSuper
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position, @NonNull List<Object> payloads) {
        if (holder instanceof EmptyViewHolder) {
            return;
        }
        ViewDataBinding binding = DataBindingUtil.getBinding(holder.itemView);
        if (isForDataBinding(payloads)) {
            binding.executePendingBindings();
        } else {
            T item = dataSource.get(position);
            onBindBinding(binding, itemBinding.variableId(), itemBinding.layoutRes(), position, item);
        }
    }

    private boolean isForDataBinding(List<Object> payloads) {
        if (payloads == null || payloads.size() == 0) {
            return false;
        }
        for (int i = 0; i < payloads.size(); i++) {
            Object obj = payloads.get(i);
            if (obj != DATA_INVALIDATION) {
                return false;
            }
        }
        return true;
    }


    @Override
    public int getItemCount() {
        if (enableShowEmptyView) {
            if (initSetting) {
                initSetting = false;
                isEmptyState = 0;
                return 0;
            } else {
                isEmptyState = (dataSource == null || dataSource.size() == 0) ? 1 : 0;
            }
            if (isEmptyState == 1) {
                return 1;
            }
        } else {
            isEmptyState = 0;
        }
        return dataSource != null ? dataSource.size() : 0;
    }


    public void checkIsEmpty() {
        if (myHandler == null) {
            myHandler = new Handler(BaseApplication.context.getMainLooper());
        }
        myHandler.postDelayed(() -> {
            if (!enableShowEmptyView) {
                if (isEmptyState == 1) {
                    //空布局 --> 恢复默认的布局
                    isEmptyState = 0;
                    //隐藏空布局
                    hideEmptyShow();
                }
                return;
            }
            if (dataSource != null && !dataSource.isEmpty()) {
                if (isEmptyState == 1) {
                    //空布局 --> 恢复默认的布局
                    isEmptyState = 0;
                    //隐藏空布局
                    hideEmptyShow();
                }
            } else {
                //如果刷新的数据为空list，则显示空布局
                if (isEmptyState != 1) {
                    //当前布局不是空布局，则刷新显示空布局
                    isEmptyState = 1;
                    adjustEmptyViewSize();
                    notifyItemInserted(0);
                }
            }
        }, 500);
    }

    private void adjustEmptyViewSize() {
        if (emptyView != null) {
            resetEmptyShow();
        }
        if (emptyView != null && emptyView.getView() != null && recyclerView != null) {
            emptyView.getView().setLayoutParams(new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        }
    }

    /**
     * 隐藏空布局
     */
    private void hideEmptyShow() {
        if (emptyView != null && emptyView.getView() != null) {
            emptyView.getView().setVisibility(View.GONE);
        }
        notifyItemRemoved(0);
    }


    private static class WeakReferenceOnListChangedCallback<T> extends ObservableList.OnListChangedCallback<ObservableList<T>> {
        final WeakReference<WithEmptyViewBindingAdapter<T>> adapterRef;

        WeakReferenceOnListChangedCallback(WithEmptyViewBindingAdapter<T> adapter, ObservableList<T> items) {
            this.adapterRef = WithEmptyAdapterReferenceCollector.createRef(adapter, items, this);
        }

        @Override
        public void onChanged(ObservableList sender) {
            WithEmptyViewBindingAdapter<T> adapter = getAdapter();
            adapter.ensureChangeOnMainThread();
            adapter.notifyDataSetChanged();
        }


        @Override
        public void onItemRangeChanged(ObservableList sender, final int positionStart, final int itemCount) {
            WithEmptyViewBindingAdapter<T> adapter = getAdapter();
            adapter.ensureChangeOnMainThread();
            adapter.notifyItemRangeChanged(positionStart, itemCount);
        }

        @Override
        public void onItemRangeInserted(ObservableList sender, final int positionStart, final int itemCount) {
            WithEmptyViewBindingAdapter<T> adapter = getAdapter();
            adapter.ensureChangeOnMainThread();
            if (adapter.enableShowEmptyView && adapter.isEmptyState == 1) {
                adapter.checkIsEmpty();
            }
            adapter.notifyItemRangeInserted(positionStart, itemCount);
        }

        @Override
        public void onItemRangeMoved(ObservableList sender, final int fromPosition, final int toPosition, final int itemCount) {
            WithEmptyViewBindingAdapter<T> adapter = getAdapter();
            adapter.ensureChangeOnMainThread();
            if (adapter.enableShowEmptyView && adapter.isEmptyState == 0) {
                adapter.checkIsEmpty();
            }
            for (int i = 0; i < itemCount; i++) {
                adapter.notifyItemMoved(fromPosition + i, toPosition + i);
            }
        }

        @Override
        public void onItemRangeRemoved(ObservableList sender, final int positionStart, final int itemCount) {
            WithEmptyViewBindingAdapter<T> adapter = getAdapter();
            adapter.ensureChangeOnMainThread();
            adapter.notifyItemRangeRemoved(positionStart, itemCount);
        }

        private WithEmptyViewBindingAdapter getAdapter() {
            if (adapterRef == null) {
                return null;
            }
            WithEmptyViewBindingAdapter<T> adapter = adapterRef.get();
            return adapter;
        }
    }


    public interface ItemIds<T> {
        long getItemId(int position, T item);
    }

    public interface ViewHolderFactory {
        RecyclerView.ViewHolder createViewHolder(ViewDataBinding binding);
    }

    protected void initLayoutManage() {
        if (recyclerView == null) {
            return;
        }
        if (null == layoutManager) {
            layoutManager = recyclerView.getLayoutManager();
            if (layoutManager instanceof GridLayoutManager) {
                final GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
                gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                    @Override
                    public int getSpanSize(int position) {
                        if (isEmptyState == 1 && enableShowEmptyView) {
                            return gridLayoutManager.getSpanCount();
                        } else {
                            return 1;
                        }

                    }
                });
            }
        }


    }

    @Override
    public void onAttachedToRecyclerView(final RecyclerView recyclerView) {
        if (this.recyclerView == null && dataSource != null && dataSource instanceof ObservableList) {
            callback = new WeakReferenceOnListChangedCallback<>(this, (ObservableList<T>) dataSource);
            ((ObservableList<T>) dataSource).addOnListChangedCallback(callback);
        }
        this.recyclerView = recyclerView;
    }

    @Override
    public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
        if (this.recyclerView != null && dataSource != null && dataSource instanceof ObservableList) {
            ((ObservableList<T>) dataSource).removeOnListChangedCallback(callback);
            callback = null;
        }
        this.recyclerView = null;
        if (myHandler != null) {
            myHandler.removeCallbacksAndMessages(null);
            myHandler = null;
        }
    }

    private void ensureChangeOnMainThread() {
        if (Thread.currentThread() != Looper.getMainLooper().getThread()) {
            throw new IllegalStateException("You must only modify the ObservableList on the main thread.");
        }
    }

    @Override
    public int getItemViewType(int position) {
        if (enableShowEmptyView) {
            if (isEmptyState == 1) {
                //空布局的类型
                return empty_view_type;
            }
        }
        itemBinding.onItemBind(position, dataSource.get(position));
        return itemBinding.layoutRes();
    }


    private static class EmptyViewHolder extends RecyclerView.ViewHolder {

        public EmptyViewHolder(@NonNull View itemView) {
            super(itemView);
        }
    }

    private static class BindingViewHolder extends RecyclerView.ViewHolder {
        public BindingViewHolder(ViewDataBinding binding) {
            super(binding.getRoot());
        }
    }

    /**
     * Set the item id's for the items. If not null, this will set {@link
     * RecyclerView.Adapter#setHasStableIds(boolean)} to true.
     */
    public void setItemIds(@Nullable ItemIds<? super T> itemIds) {
        if (this.itemIds != itemIds) {
            this.itemIds = itemIds;
            setHasStableIds(itemIds != null);
        }
    }

    @Override
    public long getItemId(int position) {
        return itemIds == null ? position : itemIds.getItemId(position, dataSource.get(position));
    }

    /**
     * Sets the lifecycle owner of this adapter to work with {@link androidx.lifecycle.LiveData}.
     * This is normally not necessary, but due to an androidx limitation, you need to set this if
     * the containing view is <em>not</em> using databinding.
     */
    public void setLifecycleOwner(@Nullable LifecycleOwner lifecycleOwner) {
        this.lifecycleOwner = lifecycleOwner;
        if (recyclerView != null) {
            for (int i = 0; i < recyclerView.getChildCount(); i++) {
                View child = recyclerView.getChildAt(i);
                ViewDataBinding binding = DataBindingUtil.getBinding(child);
                if (binding != null) {
                    binding.setLifecycleOwner(lifecycleOwner);
                }
            }
        }
    }

    private void tryGetLifecycleOwner() {
        if (lifecycleOwner == null || lifecycleOwner.getLifecycle().getCurrentState() == Lifecycle.State.DESTROYED) {
            lifecycleOwner = findLifecycleOwner(recyclerView);
        }
    }

    private LifecycleOwner findLifecycleOwner(View view) {
        ViewDataBinding binding = DataBindingUtil.findBinding(view);
        LifecycleOwner lifecycleOwner = null;
        if (binding != null) {
            lifecycleOwner = binding.getLifecycleOwner();
        }
        Context ctx = view.getContext();
        if (lifecycleOwner == null && ctx instanceof LifecycleOwner) {
            lifecycleOwner = (LifecycleOwner) ctx;
        }
        return lifecycleOwner;
    }

    /**
     * Set the factory for creating view holders. If null, a default view holder will be used. This
     * is useful for holding custom state in the view holder or other more complex customization.
     */
    public void setViewHolderFactory(@Nullable ViewHolderFactory factory) {
        viewHolderFactory = factory;
    }

    public void setEmptyView(INoDataView emptyView) {
        this.emptyView = emptyView;
    }

    public int getIsEmptyState() {
        return isEmptyState;
    }

    public boolean isEnableShowEmptyView() {
        return enableShowEmptyView;
    }

    public void setEnableShowEmptyView(boolean enableShowEmptyView) {
        this.enableShowEmptyView = enableShowEmptyView;
        checkIsEmpty();
    }

    public int getNoDataType() {
        return noDataType;
    }

    public void setNoDataType(int noDataType) {
        if (this.noDataType == noDataType) {
            return;
        }
        this.noDataType = noDataType;
        resetEmptyShow();
    }

    private void resetEmptyShow() {
        if (emptyView != null) {
            emptyView.setNoDataSrc(R.drawable.ic_error);
            emptyView.setNoDataText(recyclerView.getContext().getResources().getString(R.string.no_data));
        }
    }
}

